#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "audio.h"
#include "esp_codec_dev.h"
#include "esp_codec_dev_defaults.h"
#include "esp_log.h"
#include "hal_i2c.h"
#include "pca9557pw.h"
#include "ui_setting.h"

/***********************************************************/
/*********************    音频 ↓   *************************/

static const char *TAG = "audio";
static esp_codec_dev_handle_t play_dev_handle;   // 扬声器设备句柄
static esp_codec_dev_handle_t record_dev_handle; // 麦克风设备句柄

static i2s_chan_handle_t i2s_tx_chan = NULL;            // I2S发送通道（用于音频输出）
static i2s_chan_handle_t i2s_rx_chan = NULL;            // I2S接收通道（用于音频输入）
static const audio_codec_data_if_t *i2s_data_if = NULL; // 音频编解码器数据接口

// I2S总线初始化
// 返回值：ESP_OK成功，其他为错误代码
esp_err_t bsp_audio_init(void)
{
    esp_err_t ret = ESP_FAIL;
    // 检查I2S通道是否已初始化
    if (i2s_tx_chan && i2s_rx_chan) {
        return ESP_OK; // 已初始化则直接返回
    }

    /* 配置I2S通道参数 */
    i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(BSP_I2S_NUM, I2S_ROLE_MASTER);
    chan_cfg.auto_clear = true; // 自动清除DMA缓冲区中的旧数据
    // 创建新的I2S通道
    ESP_ERROR_CHECK(i2s_new_channel(&chan_cfg, &i2s_tx_chan, &i2s_rx_chan));

    /* 配置I2S标准模式参数 */
    const i2s_std_config_t std_cfg_default = {
        .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(16000),                              // 采样率16kHz
        .slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(32, I2S_SLOT_MODE_STEREO), // 32位数据，立体声
        .gpio_cfg = {
            .mclk = GPIO_I2S_MCLK, // 主时钟引脚
            .bclk = GPIO_I2S_SCLK, // 位时钟引脚
            .ws = GPIO_I2S_LRCK,   // 字选择（左右声道时钟）引脚
            .dout = GPIO_I2S_DOUT, // 数据输出引脚（接扬声器）
            .din = GPIO_I2S_SDIN,  // 数据输入引脚（接麦克风）
        },
    };

    /* 初始化发送通道（扬声器）*/
    if (i2s_tx_chan != NULL) {
        // 配置标准模式
        ESP_GOTO_ON_ERROR(i2s_channel_init_std_mode(i2s_tx_chan, &std_cfg_default), err, TAG, "I2S tx channel init failed");
        // 启用通道
        ESP_GOTO_ON_ERROR(i2s_channel_enable(i2s_tx_chan), err, TAG, "I2S tx channel enable failed");
    }

    /* 初始化接收通道（麦克风）*/
    if (i2s_rx_chan != NULL) {
        // 配置标准模式
        ESP_GOTO_ON_ERROR(i2s_channel_init_std_mode(i2s_rx_chan, &std_cfg_default), err, TAG, "I2S rx channel init failed");
        // 启用通道
        ESP_GOTO_ON_ERROR(i2s_channel_enable(i2s_rx_chan), err, TAG, "I2S rx channel enable failed");
    }

    /* 配置音频编解码器的I2S数据接口 */
    audio_codec_i2s_cfg_t i2s_cfg = {
        .port = BSP_I2S_NUM,      // I2S端口号
        .rx_handle = i2s_rx_chan, // 接收通道句柄
        .tx_handle = i2s_tx_chan, // 发送通道句柄
    };
    // 创建I2S数据接口
    i2s_data_if = audio_codec_new_i2s_data(&i2s_cfg);
    if (i2s_data_if == NULL) {
        goto err; // 创建失败则跳转到错误处理
    }

    return ESP_OK; // 初始化成功

err: // 错误处理
    // 清理已分配的I2S通道
    if (i2s_tx_chan) {
        i2s_del_channel(i2s_tx_chan);
    }
    if (i2s_rx_chan) {
        i2s_del_channel(i2s_rx_chan);
    }

    return ret; // 返回错误状态
}

// 初始化音频输出芯片（扬声器）
// 返回：扬声器设备句柄
esp_codec_dev_handle_t bsp_audio_codec_speaker_init(void)
{
    // 确保I2S已初始化
    if (i2s_data_if == NULL) {
        ESP_ERROR_CHECK(bsp_audio_init()); // 初始化I2S
    }
    assert(i2s_data_if); // 断言确保数据接口有效

    // 获取GPIO控制接口
    const audio_codec_gpio_if_t *gpio_if = audio_codec_new_gpio();

    // 配置I2C控制接口
    audio_codec_i2c_cfg_t i2c_cfg = {
        .port = BSP_I2C_NUM,               // I2C端口号
        .addr = ES8311_CODEC_DEFAULT_ADDR, // ES8311编解码器地址
    };
    const audio_codec_ctrl_if_t *i2c_ctrl_if = audio_codec_new_i2c_ctrl(&i2c_cfg);
    assert(i2c_ctrl_if); // 断言确保I2C控制接口有效

    // 配置硬件增益参数
    esp_codec_dev_hw_gain_t gain = {
        .pa_voltage = 5.0,        // 功放电压
        .codec_dac_voltage = 3.3, // DAC工作电压
    };

    // 配置ES8311编解码器参数
    es8311_codec_cfg_t es8311_cfg = {
        .ctrl_if = i2c_ctrl_if,                    // I2C控制接口
        .gpio_if = gpio_if,                        // GPIO接口
        .codec_mode = ESP_CODEC_DEV_WORK_MODE_DAC, // 工作模式为DAC（音频输出）
        .pa_pin = GPIO_PWR_CTRL,                   // 功放使能引脚
        .pa_reverted = false,                      // 功放控制极性（false=高电平使能）
        .master_mode = false,                      // 从模式（由I2S提供时钟）
        .use_mclk = true,                          // 使用主时钟
        .digital_mic = false,                      // 不使用数字麦克风
        .invert_mclk = false,                      // 不反转MCLK时钟
        .invert_sclk = false,                      // 不反转SCLK时钟
        .hw_gain = gain,                           // 硬件增益配置
    };
    // 创建ES8311编解码器实例
    const audio_codec_if_t *es8311_dev = es8311_codec_new(&es8311_cfg);
    assert(es8311_dev); // 断言确保创建成功

    // 配置音频设备参数
    esp_codec_dev_cfg_t codec_dev_cfg = {
        .dev_type = ESP_CODEC_DEV_TYPE_OUT, // 设备类型为输出（扬声器）
        .codec_if = es8311_dev,             // 编解码器接口
        .data_if = i2s_data_if,             // 数据接口（I2S）
    };
    return esp_codec_dev_new(&codec_dev_cfg); // 创建并返回音频设备句柄
}

// 初始化音频输入芯片（麦克风）
// 返回：麦克风设备句柄
esp_codec_dev_handle_t bsp_audio_codec_microphone_init(void)
{
    // 确保I2S已初始化
    if (i2s_data_if == NULL) {
        ESP_ERROR_CHECK(bsp_audio_init()); // 初始化I2S
    }
    assert(i2s_data_if); // 断言确保数据接口有效

    // 配置I2C控制接口
    audio_codec_i2c_cfg_t i2c_cfg = {
        .port = BSP_I2C_NUM, // I2C端口号
        .addr = 0x82,        // ES7210编解码器地址
    };
    const audio_codec_ctrl_if_t *i2c_ctrl_if = audio_codec_new_i2c_ctrl(&i2c_cfg);
    assert(i2c_ctrl_if); // 断言确保I2C控制接口有效

    // 配置ES7210编解码器参数
    es7210_codec_cfg_t es7210_cfg = {
        .ctrl_if = i2c_ctrl_if,                                                                // I2C控制接口
        .mic_selected = ES7120_SEL_MIC1 | ES7120_SEL_MIC2 | ES7120_SEL_MIC3 | ES7120_SEL_MIC4, // 启用所有4个麦克风
    };
    // 创建ES7210编解码器实例
    const audio_codec_if_t *es7210_dev = es7210_codec_new(&es7210_cfg);
    assert(es7210_dev); // 断言确保创建成功

    // 配置音频设备参数
    esp_codec_dev_cfg_t codec_es7210_dev_cfg = {
        .dev_type = ESP_CODEC_DEV_TYPE_IN, // 设备类型为输入（麦克风）
        .codec_if = es7210_dev,            // 编解码器接口
        .data_if = i2s_data_if,            // 数据接口（I2S）
    };
    return esp_codec_dev_new(&codec_es7210_dev_cfg); // 创建并返回音频设备句柄
}

// 设置音频采样参数（采样率/位宽/声道）
// 参数：rate-采样率, bits_cfg-位宽, ch-声道模式
// 返回：操作结果（ESP_OK成功）
esp_err_t bsp_codec_set_fs(uint32_t rate, uint32_t bits_cfg, i2s_slot_mode_t ch)
{
    esp_err_t ret = ESP_OK;

    // 配置采样参数结构体
    esp_codec_dev_sample_info_t fs = {
        .sample_rate = rate,         // 采样率
        .channel = ch,               // 声道模式
        .bits_per_sample = bits_cfg, // 位宽
    };

    // 关闭并重新打开设备以应用新参数
    if (play_dev_handle) {
        ret = esp_codec_dev_close(play_dev_handle); // 关闭扬声器
    }
    if (record_dev_handle) {
        ret |= esp_codec_dev_close(record_dev_handle);                                 // 关闭麦克风
        ret |= esp_codec_dev_set_in_gain(record_dev_handle, CODEC_DEFAULT_ADC_VOLUME); // 设置默认ADC增益
    }

    // 重新打开设备
    if (play_dev_handle) {
        ret |= esp_codec_dev_open(play_dev_handle, &fs); // 用新参数打开扬声器
    }
    if (record_dev_handle) {
        ret |= esp_codec_dev_open(record_dev_handle, &fs); // 用新参数打开麦克风
    }
    return ret; // 返回操作结果
}

// 音频编解码器初始化（主入口）
// 返回：操作结果（ESP_OK成功）
esp_err_t bsp_codec_init(void)
{
    // 初始化扬声器
    play_dev_handle = bsp_audio_codec_speaker_init();
    assert((play_dev_handle) && "speaker init failed"); // 断言验证

    // 初始化麦克风
    record_dev_handle = bsp_audio_codec_microphone_init();
    assert((record_dev_handle) && "microphone init failed"); // 断言验证

    // 设置默认采样参数（采样率/位宽/声道）
    bsp_codec_set_fs(CODEC_DEFAULT_SAMPLE_RATE, CODEC_DEFAULT_BIT_WIDTH, CODEC_DEFAULT_CHANNEL);
    // 设置默认音量
    esp_codec_dev_set_out_vol(play_dev_handle, VOLUME_DEFAULT);

    return ESP_OK; // 初始化成功
}

// 播放音频数据
// 参数：audio_buffer-音频数据缓冲区, len-数据长度, bytes_written-实际写入长度, timeout_ms-超时时间
// 返回：操作结果
esp_err_t bsp_i2s_write(void *audio_buffer, size_t len, size_t *bytes_written, uint32_t timeout_ms)
{
    esp_err_t ret = ESP_OK;
    // 通过扬声器设备写入数据
    ret = esp_codec_dev_write(play_dev_handle, audio_buffer, len);
    *bytes_written = len; // 设置实际写入长度（简化处理）
    return ret;
}

// 设置静音状态
// 参数：enable-true静音/false取消静音
// 返回：操作结果
esp_err_t bsp_codec_mute_set(bool enable)
{
    return esp_codec_dev_set_out_mute(play_dev_handle, enable); // 调用设备静音接口
}

// 设置音量
// 参数：volume-音量值, volume_set-实际设置值（未使用）
// 返回：操作结果
esp_err_t bsp_codec_volume_set(int volume, int *volume_set)
{
    return esp_codec_dev_set_out_vol(play_dev_handle, (int)volume); // 调用设备音量设置
}

// 获取麦克风通道数量
// 返回：通道数量（常量值）
int bsp_get_feed_channel(void)
{
    return ADC_I2S_CHANNEL; // 返回预定义的通道数
}

// 获取麦克风数据并进行通道重排
// 参数：is_get_raw_channel-是否获取原始数据, buffer-数据缓冲区, buffer_len-缓冲区长度
// 返回：操作结果
esp_err_t bsp_get_feed_data(bool is_get_raw_channel, int16_t *buffer, int buffer_len)
{
    esp_err_t ret = ESP_OK;
    // 计算音频块数量（每个块包含ADC_I2S_CHANNEL个通道的样本）
    int audio_chunksize = buffer_len / (sizeof(int16_t) * ADC_I2S_CHANNEL);

    // 从麦克风读取原始数据（4通道）
    ret = esp_codec_dev_read(record_dev_handle, (void *)buffer, buffer_len);

    // 如果不是获取原始数据，则进行通道重排（4通道->3通道）
    if (!is_get_raw_channel) {
        for (int i = 0; i < audio_chunksize; i++) {
            int16_t ref = buffer[4 * i + 0]; // 保存参考通道（如第0通道）
            // 通道重排：将第1通道移到位置0，第3通道移到位置1，参考通道放到位置2
            buffer[3 * i + 0] = buffer[4 * i + 1];
            buffer[3 * i + 1] = buffer[4 * i + 3];
            buffer[3 * i + 2] = ref;
        }
    }

    return ret; // 返回读取结果
}

// // 获取麦克风数据并进行通道重排
// // 参数： buffer-数据缓冲区, buffer_len-缓冲区长度 ,data_len 实际数据长度
// // 返回：操作结果
// esp_err_t get_voice_record_data(int16_t *buffer, int buffer_len, int *data_len)
// {
//     esp_err_t ret = ESP_OK;
//     // 计算音频块数量（每个块包含ADC_I2S_CHANNEL个通道的样本）
//     int audio_chunksize = buffer_len / (sizeof(int16_t) * ADC_I2S_CHANNEL);
//     *data_len = buffer_len/2;
//     // 从麦克风读取原始数据（4通道）
//     //ret = esp_codec_dev_read(record_dev_handle, (void *)buffer, buffer_len);

//     ret = esp_codec_dev_read(record_dev_handle, (void *)buffer, buffer_len);

//     // 如果不是获取原始数据，则进行通道重排（4通道->3通道）
//     for (int i = 0; i < audio_chunksize; i++)
//     {
//         // 通道重排：取第1、2通道
//         buffer[2 * i + 0] = buffer[4 * i + 0];
//         buffer[2 * i + 1] = buffer[4 * i + 1];
//     }

//     return ret; // 返回读取结果
// }
/*
 *@brief 恢复语音控制的i2s配置
*/
void renew_codec_fs(void)
{
    // 设置默认采样参数（采样率/位宽/声道）
    bsp_codec_set_fs(CODEC_DEFAULT_SAMPLE_RATE, CODEC_DEFAULT_BIT_WIDTH, CODEC_DEFAULT_CHANNEL);
}
bool i2s_fs_is_default(uint32_t rate, uint32_t bits_cfg, uint32_t ch)
{
    if (CODEC_DEFAULT_SAMPLE_RATE==rate && CODEC_DEFAULT_BIT_WIDTH==bits_cfg && CODEC_DEFAULT_CHANNEL==ch)
    {
        return false;
    }
    return true;
}

    // 声明开机音乐PCM数据（由二进制文件嵌入）
    extern const uint8_t music_pcm_start[] asm("_binary_sword_pcm_start");
extern const uint8_t music_pcm_end[] asm("_binary_sword_pcm_end");

// 错误原因描述
static const char err_reason[][30] = {
    "input param is invalid", // 参数错误
    "operation timeout"       // 操作超时
};

// 开机音乐播放任务
void power_music_task(void *pvParameters)
{
    esp_err_t ret = ESP_OK;
    size_t bytes_write = 0;
    uint8_t *data_ptr = (uint8_t *)music_pcm_start; // 指向音乐数据起始位置
    bsp_codec_set_fs(CODEC_DEFAULT_SAMPLE_RATE, 16, CODEC_DEFAULT_CHANNEL); // 设置音频参数为开机音乐参数
    /* 预加载策略：禁用发送通道并预加载数据，确保音频连续输出 */
    // 禁用发送通道
    ESP_ERROR_CHECK(i2s_channel_disable(i2s_tx_chan));
    // 预加载首块数据到DMA缓冲区
    ESP_ERROR_CHECK(i2s_channel_preload_data(i2s_tx_chan, data_ptr, music_pcm_end - data_ptr, &bytes_write));
    data_ptr += bytes_write; // 移动数据指针

    /* 启用发送通道（开始传输预加载数据）*/
    ESP_ERROR_CHECK(i2s_channel_enable(i2s_tx_chan));

    pa_en(1); // 使能功放（PA_EN引脚置高）

    /* 写入剩余的音乐数据 */
    ret = i2s_channel_write(i2s_tx_chan, data_ptr, music_pcm_end - data_ptr, &bytes_write, portMAX_DELAY);
    if (ret != ESP_OK) {
        // 处理错误（仅超时可能发生）
        ESP_LOGE(TAG, "[music] open music play failed: %s", err_reason[ret == ESP_ERR_TIMEOUT]);
        abort(); // 严重错误终止程序
    }
    // 检查实际写入字节数
    if (bytes_write > 0) {
        ESP_LOGI(TAG, "[music] open music play completed: %d", bytes_write);
    } else {
        ESP_LOGE(TAG, "[music] open music play failed: no data");
        abort();
    }

    pa_en(0); // 关闭功放
    /* 清理资源 */
    //i2s_channel_disable(i2s_tx_chan);

   
    is_open_voice_control(); //根据配置决定是否开启语音控制
    // 设置事件标志（通知其他任务音乐播放完成）
    //xEventGroupSetBits(my_event_group, START_MUSIC_COMPLETED);
    vTaskDelete(NULL); // 删除自身任务
}

    /*********************    音频 ↑   *************************/
    /***********************************************************/

i2s_chan_handle_t get_i2s_tx_chan(void)
{
    return i2s_tx_chan;
}
i2s_chan_handle_t get_i2s_rx_chan(void)
{
    return i2s_rx_chan;
}


/*恢复语音控制的i2s配置*/



/*************************************录音机code********************************************/

void voive_i2s_fs_init(void)
{
    bsp_codec_set_fs(VOICE_I2S_SAMPLE_RATE, VOICE_I2S_SAMPLE_BITS, VOICE_I2S_CHAN_NUM);
}


/*************************************录音机code end********************************************/


